#pragma once
#include "resource_mgr.h"
#include "macros.h"

#include <SDL2/SDL.h>
#include <array>
#include <vector>
#include <filesystem>
#include <fstream>
#include <memory>

#define TOTAL_LEVEL_COUNT	55

class Player;

/************************************************************************/
/* 游戏逻辑类
/************************************************************************/


enum GroundObjectState {
	GroundObjectState_Normal = 0,					//常规状态
	GroundObjectState_Disappearing,					//消失
	GroundObjectState_Appearing,					//可显示
	GroundObjectState_InBattle,						//战斗中
	GroundOhjectState_Unknown1,						//代码中未见到使用此值
	GroundObjectState_Unknown2,						//代码中使用过此值但只有一处赋值看不到访问
};

//地面物品
struct GroundObject {
	int objectId = -1;								//物品Id,物品表下标
	bool alive = true;								//是否仍然存活 怪物被消灭，门被打开，物品被吃掉则消失
	GroundObjectState state = GroundObjectState_Normal;	//状态
	int x = -1;										//位置 x
	int y = -1;										//位置 y
	short npcFlag = -1;								//npc标志位，不同的值代表了不同npc的功能，不同的位也有不同的作用，具体解析见相关代码
	bool bVisible = true;							//是否可见，默认为true
	//冗余存储一些Actor的属性，因为这些属性可能会根据对象状态的不同而被修改，需要单独记录
	int animSequenceIndex;							//动画序列帧数组下标
	int currFrameIndex = 0;							//当前序列帧下标
	int frameWidth = -1;							//每一帧宽度
	int frameHeight = -1;							//每一帧高度
	ActorType actorType;							//类型	

	//初始化其余属性
	void initPropertys();
	//设置消失标志
	void setDisappear();
	//设置出现标志
	void setAppear();
	//驱动动画序列帧
	void nextAnim();
	//获取动画序列帧当前下标
	int getAnimIndex();
};

//地图属性
struct MapData {
	int mapWidth = 0;									//地图宽度
	int mapHeight = 0;									//地图高度
	std::vector<std::vector<bool>> m_mapCollisionArray;	//地图碰撞信息
	std::vector<GroundObject> m_objects;				//地面物品信息
	std::vector<std::vector<int>> m_tileInfo;			//图块信息
	std::vector<char> mapTileIndexArray;				//tile图块信息
	std::vector<char> mapTileTransformArray;			//tile图块变换信息
};

//游戏运行时数据，包括角色数据
struct GameState {
	int level = -1;										//游戏层数
	int difficulity = 0;								//难度数组下标
	std::vector<std::shared_ptr<MapData>> maps;			//地图数据
	std::shared_ptr<Player> m_player;				//角色属性
	int equipOffsetY = 0;								//当前的偏移量
	bool bFloatingUp = true;							//是否向上浮动
	std::shared_ptr<SDL_Texture> gameTexture;				//游戏texture
};

class Game {
public:
	Game(const std::filesystem::path& exePath);
	~Game();
public:
	bool init();
	void cleanup();
	bool createWindow(int width, int height);
	bool initResources();
	//执行消息循环
	void exec();
	//绘制游戏
	void paintGame();
	//开启动画定时器
	void startAnimTimer(int interval);
	//关闭动画定时器
	void stopAnimTimer();
	//开启浮动动画定时器
	void startFloatingTimer(int interval);
	//关闭浮动动画定时器
	void stopFloatingTimer();
	//处理游戏逻辑
	void processGamelogic(int interval);

	bool loadLevel(int level);
	void initPassthrough(int width, int height, const std::vector<char>& passableArray, std::vector<std::vector<bool>>& result);

	bool loadLevelSprites(const std::shared_ptr<MapData>& pMapData, const std::filesystem::path& basePath, int nLevel);

	bool paintObject(GroundObject& obj);
	//切换场景
	void changeLevel(int level);
	//判断是否可以同行
	bool checkMapPassable(int x, int y);
	//获取指定逻辑坐标位置的对象集合
	std::vector<GroundObject*> getGroundObjectsAtPosition(int x, int y);
	//绘制玩家
	bool paintPlayer();

private:
	//计算HP削减量
	int caculateHpReduce(int objectId, bool bFlag);
	//获取真实攻击力(某些怪物被特定物品克制，会受到加倍伤害)
	int getRealAttack(int objectId);
	//与怪物战斗
	int battle(int playerAttack, int playerDef, int monsterHp, int monsterAttack, int monsterDef, bool bFlag);
	//获取属性物品的属性增加值（威力丹/金刚丹等）
	int getPropertyItemValue();
	//使用地面物品
	void pickupGroundItem(int objectId);
	//装备物品
	void equipItem(int objectId);
	//判断角色是否拥有特定物品
	int getBagItemIndex(int objectId);
	//更换武器和防具
	bool changeEquipWeaponCloth(int newEquipIndex, bool forceEquip);
	//显示错误字符串
	void showGameInfoString(const std::string& errorString);
	//尝试摧毁周围一格内的特定对象
	bool tryDestroyAroundObjects(int objectId);
	//使用背包物品
	bool useBagItem(int itemType);
	//杀死怪物
	bool killMonster(int x, int y);
	//干掉
	bool killMonster(GroundObject& obj);
	//交易
	bool trade(int objectId, bool bConfirm);
	//使用金钱
	bool useMoney(int money);
	//修改钥匙数量
	bool changeKeyCount(enum KeyType type, int count);
	//标记封印门开启
	bool markMonsterDoorWillOpen(int npcFlag, std::vector<int> openDoorIndexs);
	//绘制sprite
	void paintSprite(std::shared_ptr<GLTexture> pTexture, int destX, int destY, int srcX, int srcY, int width, int height);
	//绘制sprite，直接将真个texture贴上去
	void paintSprite(std::shared_ptr<GLTexture> pTexture, int destX, int destY);
	//移动角色
	bool activeObject(int x, int y);


protected:
	inline short readBinaryShort(std::ifstream& fs)
	{
		return fs.get() & 0xFF | fs.get() << 8 & 0xFF00;
	}


private:
	std::filesystem::path m_srcRoot;				//资源根路径
	std::filesystem::path m_dataRoot;				//配置文件根路径
	SDL_Window* m_window = nullptr;
	SDL_GLContext gl_context = nullptr;
	const char* glsl_version = nullptr;

	GameState m_gameData;						//游戏运行时信息
	SDL_TimerID m_floatingTimer = 0;				//浮动动画定时器ID
	SDL_TimerID m_animTimer = 0;					//动画定时器ID
	Uint32 m_logicTimestamp = 0;					//逻辑处理时间戳

};